# ScrollArea - Container that has scrollbars and allows content to be scrolled
# Copyright (C) 2007 Lauri Taimila
# 
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
# 
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
# 
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.

__licence__ = "GPLv2"
__copyright__ = "2007, Lauri Taimila"
__author__ = "Lauri Taimila <lauri@taimila.com>"

import clutter
from frontend.gui.widgets.arrow_texture import ArrowTexture
from frontend.gui.widgets.list_indicator import ListIndicator

class ScrollArea(clutter.Group):
    """
    ScrollArea widget.
    
    Container for clutter.Actors. This widget can contain many actors and
    allows scrolling those actors if not all fit in the widget area.
    """

    def __init__(self, width, height, theme):
        """
        Initialize scroll area widget
        @param width: Width of the content (widget is a bit bigger than this)
        @param height: Height of the content (widget is a bit bigger than this)
        @param scroll_bar_location: Location for scrollbar (see class attributes)
        """
        clutter.Group.__init__(self)
        self.offset = 0 # Determines current position of the view
        self.step_size = 30
        self.content_group = None
        self.area_width = width
        self.area_height = height
        self.active = False;
        
        # Use transparent rectangle to set size of the scroll area
        # FIXME: Is there another way? This seems a bit hackish solution.
        rect = clutter.Rectangle()
        rect.set_size(width, height)
        rect.set_color(clutter.Color(0,0,0,0))
        rect.show()
        self.add(rect)
        
        # Create content position indicator
        self.indicator = ListIndicator(0.2, 0.045, theme, ListIndicator.VERTICAL)
        self.indicator.hide_position()
        self.indicator.set_current(1)
        self.indicator.set_position(width - self.indicator.get_width(), height + 10)
        self.add(self.indicator)
    
    def set_active(self, boolean):
        """
        Set this widget active / inactive. When inactive indicator is hidden.
        """
        self.active = boolean
        if boolean:
            self.indicator.show()
        else:
            self.indicator.hide()
        
    def is_active(self):
        """
        Is this widget active.
        """
        return self.active
    
    def set_content(self, group):
        """
        Set content into scroll area.
        @param group: Group of clutter Actors (clutter.Group)
        """
        if self.content_group is not None:
            self.remove(self.content_group)
        
        self.content_group = group    
        self.content_group.show()
        self.add(group)
        self.content_group.set_clip(0, 0, self.area_width, self.area_height)
        tmp = (self.content_group.get_height() - self.area_height) / self.step_size
        self.indicator.set_maximum(tmp + 2)
        
        # Do not show indicator if there is no need for scrolling
        if self.content_group.get_height() < self.area_height:
            self.indicator.hide()
    
    def get_content(self):
        """
        Get scroll area content.
        @return: Group of actors (clutter.Group)
        """
        self.content_group
        
    def set_content_size(self, width, height):
        """
        Set content size. This is the size of the content area NOT widget.
        @param width: Width of the content area
        @param height: Height of the content area
        """
        #FIXME: Implement this method
    
    def set_step_size(self, size):
        """
        Set step size. Stepsize determines how much content is scrolled once.
        @param size: Size in pixels (integer)
        """
        self.step_size = size
        if self.content_group is not None:
            tmp = (self.content_group.get_height() - self.area_height) / self.step_size
            self.indicator.set_maximum(tmp + 2)
        
    def get_step_size(self):
        """
        Get step size
        @requires: Step size (Integer)
        """
        return self.step_size
    
    def get_offset(self):
        """
        Get current offset value. This value determines how many pixels current
        view is from the absolute top.
        @return: Integer
        """
        return self.offset
           
    def scroll_to_top(self):
        """
        Scroll content back to top. This is intial state of the scroll area.
        """
        self.indicator.set_current(1)
        self.offset = 0
        self.content_group.set_clip(0, 0, self.area_width, self.area_height)
        self.content_group.set_position(0,0)
        self.content_group.set_width(self.area_width)
        
    def scroll_to_bottom(self):
        """
        Scroll content as much as possible.
        """
        self.indicator.set_current(self.indicator.get_maximum())
        self.offset = self.content_group.get_height() - self.area_height
        self.content_group.set_clip(0, self.content_group.get_height() - self.area_height, self.area_width, self.area_height)
        self.content_group.set_position(0,-(self.content_group.get_height() - self.area_height))
        self.content_group.set_width(self.area_width)
    
    def scroll_up(self):
        """Scroll up by one step size."""
        if self.content_group is not None:
            if self.offset - self.step_size >= 0:
                self.indicator.set_current(self.indicator.get_current() - 1)
                self.offset = self.offset - self.step_size
                self.content_group.set_clip(0, self.offset, self.area_width, self.area_height)
                self.content_group.move_by(0, self.step_size)
                self.content_group.set_width(self.area_width)
                
            # If there is a smaller gap than step size between current position and the top
            elif self.offset > 0: 
                self.indicator.set_current(1)
                self.offset = 0
                self.content_group.set_clip(0, 0, self.area_width, self.area_height)
                self.content_group.set_position(0,0)
                self.content_group.set_width(self.area_width)
        else:
            raise Exception("No content")
        
    def scroll_down(self):
        """Scroll down by one step size."""
        if self.content_group is not None:
            if self.offset + self.step_size <= self.content_group.get_height() - self.area_height:
                self.indicator.set_current(self.indicator.get_current() + 1)
                self.offset = self.offset + self.step_size
                self.content_group.set_clip(0, self.offset, self.area_width, self.area_height)
                self.content_group.move_by(0, -self.step_size)
                self.content_group.set_width(self.area_width)
                
            # If there is a smaller gap than step size between current position and the bottom
            elif self.offset < self.content_group.get_height() - self.area_height:
                difference = (self.content_group.get_height() - self.area_height) - self.offset
                self.indicator.set_current(self.indicator.get_maximum())
                self.offset = self.content_group.get_height() - self.area_height
                self.content_group.set_clip(0, self.offset, self.area_width, self.area_height)
                self.content_group.move_by(0, -difference)
                self.content_group.set_width(self.area_width)
        else:
            raise Exception("No content")
        
    def scroll_page_up(self):
        """Scroll up by one page. Page is a scroll area height."""
        if self.content_group is not None:
            if self.offset - self.area_height >= 0:
                self.indicator.set_current(self.indicator.get_current() - 1)
                self.offset = self.offset - self.area_height
                self.content_group.set_clip(0, self.offset, self.area_width, self.area_height)
                self.content_group.move_by(0, self.area_height)
                self.content_group.set_width(self.area_width)
                
            # If there is a smaller gap than step size between current position and the top
            elif self.offset > 0: 
                self.indicator.set_current(1)
                self.offset = 0
                self.content_group.set_clip(0, 0, self.area_width, self.area_height)
                self.content_group.set_position(0,0)
                self.content_group.set_width(self.area_width)
        else:
            raise Exception("No content")
        
    def scroll_page_down(self):
        """Scroll down by one page. Page is a scroll area height."""
        if self.content_group is not None:
            if self.offset + self.area_height <= self.content_group.get_height() - self.area_height:
                self.indicator.set_current(self.indicator.get_current() + 1)
                self.offset = self.offset + self.area_height
                self.content_group.set_clip(0, self.offset, self.area_width, self.area_height)
                self.content_group.move_by(0, -self.area_height)
                self.content_group.set_width(self.area_width)
                
            # If there is a smaller gap than step size between current position and the bottom
            elif self.offset < self.content_group.get_height() - self.area_height:
                difference = (self.content_group.get_height() - self.area_height) - self.offset
                self.indicator.set_current(self.indicator.get_maximum())
                self.offset = self.content_group.get_height() - self.area_height
                self.content_group.set_clip(0, self.offset, self.area_width, self.area_height)
                self.content_group.move_by(0, -difference)
                self.content_group.set_width(self.area_width)
        else:
            raise Exception("No content")